package sg.edu.nus.iss.billing.common.validation;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 
 * @author Cherry
 *
 */
public class ValidateCommonUtil {
	
	public static boolean notEmpty(String s) {
	 return (s != null && s.length() > 0);
	}
	
	public static boolean checkMobileNum(String mobileNum) {
		if (mobileNum.length() != 8)
			return false;
		else {
			if (mobileNum.charAt(0) != '9' && mobileNum.charAt(0) != '8' && mobileNum.charAt(0) != '3')
				return false;
			else {
				for (int i = 1; i < 8; i++) {
					if (!Character.isDigit(mobileNum.charAt(i))) {
						return false;
					}
				}
			}

			return true;
		}
	}

	public static boolean checkTelNum(String telNum) {
		if (telNum.length() != 8 || notEmpty(telNum))
			return false;
		else {
			if (telNum.charAt(0) != '6' && telNum.charAt(0) != '3'){
					return false;
			}
			
			for (int i = 1; i < 8; i++) {
				if (!Character.isDigit(telNum.charAt(i))) {
					return false;
				}
			}

			return true;
		}
	}

	// Check NRIC for Singaporean/Permanent Residents
	public static boolean checkSGNricNum(String nricNum) {
		boolean check = false;

		if (nricNum.length() != 9)
			return false;
		else {
			if (Character.toLowerCase(nricNum.charAt(0)) != 's') {
				if(Character.toLowerCase(nricNum.charAt(0)) != 't'){
					check = false;
				}
				else
					check = true;
			} 
			else
				check = true;

			if (check) {
				for (int i = 1; i < 8; i++) {
					if (!Character.isDigit(nricNum.charAt(i))) {
						return false;
					}
				}

				int total = (2 * Integer.parseInt(Character.toString(nricNum.charAt(1))))
						+ (7 * Integer.parseInt(Character.toString(nricNum.charAt(2))))
						+ (6 * Integer.parseInt(Character.toString(nricNum.charAt(3))))
						+ (5 * Integer.parseInt(Character.toString(nricNum.charAt(4))))
						+ (4 * Integer.parseInt(Character.toString(nricNum.charAt(5))))
						+ (3 * Integer.parseInt(Character.toString(nricNum.charAt(6))))
						+ (2 * Integer.parseInt(Character.toString(nricNum.charAt(7))));

				if (Character.toLowerCase(nricNum.charAt(0)) == 't')
					total += 4;

				switch (total % 11) {
				case 0:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'j')
						return true;
					else
						return false;
				case 1:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'z')
						return true;
					else
						return false;
				case 2:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'i')
						return true;
					else
						return false;
				case 3:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'h')
						return true;
					else
						return false;
				case 4:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'g')
						return true;
					else
						return false;
				case 5:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'f')
						return true;
					else
						return false;
				case 6:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'e')
						return true;
					else
						return false;
				case 7:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'd')
						return true;
					else
						return false;
				case 8:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'c')
						return true;
					else
						return false;
				case 9:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'b')
						return true;
					else
						return false;
				case 10:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'a')
						return true;
					else
						return false;
				default:
					return false;
				}
			} else
				return false;
		}
	}

	// Check NRIC for Non-Singapore Citizens
	public static boolean checkNSNricNum(String nricNum) {
		boolean check = false;

		if (nricNum.length() != 9)
			return false;
		else {
			if (Character.toLowerCase(nricNum.charAt(0)) != 'f'){
				if(Character.toLowerCase(nricNum.charAt(0)) != 'g'){
					check = false;
				}
				else
					check = true;
			}	
			else
				check = true;

			if (check) {
				for (int i = 1; i < 8; i++) {
					if (!Character.isDigit(nricNum.charAt(i))) {
						return false;
					}
				}

				int total = (2 * Integer.parseInt(Character.toString(nricNum.charAt(1))))
						+ (7 * Integer.parseInt(Character.toString(nricNum.charAt(2))))
						+ (6 * Integer.parseInt(Character.toString(nricNum.charAt(3))))
						+ (5 * Integer.parseInt(Character.toString(nricNum.charAt(4))))
						+ (4 * Integer.parseInt(Character.toString(nricNum.charAt(5))))
						+ (3 * Integer.parseInt(Character.toString(nricNum.charAt(6))))
						+ (2 * Integer.parseInt(Character.toString(nricNum.charAt(7))));

				if (Character.toLowerCase(nricNum.charAt(0)) == 'g')
					total += 4;

				switch (total % 11) {
				case 0:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'x')
						return true;
					else
						return false;
				case 1:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'w')
						return true;
					else
						return false;
				case 2:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'u')
						return true;
					else
						return false;
				case 3:
					if (Character.toLowerCase((nricNum.charAt(8))) == 't')
						return true;
					else
						return false;
				case 4:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'r')
						return true;
					else
						return false;
				case 5:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'q')
						return true;
					else
						return false;
				case 6:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'p')
						return true;
					else
						return false;
				case 7:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'n')
						return true;
					else
						return false;
				case 8:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'm')
						return true;
					else
						return false;
				case 9:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'l')
						return true;
					else
						return false;
				case 10:
					if (Character.toLowerCase((nricNum.charAt(8))) == 'k')
						return true;
					else
						return false;
				default:
					return false;
				}
			} else
				return false;
		}
	}

	public static boolean checkEmail(String email) {

		// Set the email pattern string
		Pattern p = Pattern.compile(".+@.+\\.[\\w\\d]+");

		// Match the given string with the pattern
		Matcher m = p.matcher(email);

		// check whether match is found
		boolean matchFound = m.matches();

		if (matchFound)
			return true;
		else
			return false;
	}

	private static final long BEFOREMIDNIGHT = (24 * 60 * 60 * 1000) - 1;

	private static DateFormat getDateFormat() {
		return new SimpleDateFormat("dd/MM/yyyy");
	}

	private static DateFormat getDateTimeFormat() {
		return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
	}

	public static Date parseDate(String date) {
		Date dateObject = null;

		if (date != null) {
			try {
				dateObject = getDateFormat().parse(date);
			} catch (ParseException ex) {
				dateObject = null;
				//logger.error("Error parsing date string: " + date, ex);
			}
		}

		return dateObject;
	}

	public static Date parseDateTime(String date) {
		Date dateObject = null;

		if (date != null) {
			try {
				dateObject = getDateTimeFormat().parse(date);
			} catch (ParseException ex) {
				dateObject = null;
				//logger.error("Error parsing date string: " + date, ex);
			}
		}

		return dateObject;
	}

	public static String formatDate(Date date) {
		String result = "";

		if (date != null) {
			result = getDateFormat().format(date);
		}

		return result;
	}

	public static String formatDateTime(Date date) {
		String result = "";

		if (date != null) {
			result = getDateTimeFormat().format(date);
		}

		return result;
	}

	public static Date parseStartDateTime(Date date) {
		if (date != null) {
			return parseDateTime(formatDate(date) + " 0:0:0");
		} else {
			return date;
		}
	}

	public static Date parseEndDateTime(Date date) {
		if (date != null) {
			return parseDateTime(formatDate(date) + " 23:59:59");
		} else {
			return date;
		}
	}

	/**
	 * Appends time to the given date. For example "22-10-2008" become
	 * "22-10-2008 23:59:59".
	 */
	public static Date appendMaxTime(Date date) {
		if (date == null)
			return null;

		return new Date(date.getTime() + BEFOREMIDNIGHT);
	}

	// For Applications, UEN Stripping
	public static List<String> stripUen(String uenNum, List<String> checkedPremise) {
		List<String> hdbRefNoList = new ArrayList<String>();
		
		if (checkedPremise != null) {
			for (String s : checkedPremise) {
				if(s.length() != 11){
					String tempUen = "";
					String tempNum = "";
					int breakPoint = 0;
	
					for (int i = 0; i < s.length(); i++) {
						if (s.charAt(i) != '|')
							tempUen += s.charAt(i);
						else {
							breakPoint = i + 1;
							break;
						}
					}
	
					if (tempUen.equalsIgnoreCase(uenNum)) {
						for (int i = breakPoint; i < s.length(); i++)
							tempNum += s.charAt(i);
	
						hdbRefNoList.add(tempNum);
					}
				}
				else{
					hdbRefNoList.add(s);
				}
			}
		}

		return hdbRefNoList;
	}
	
	public static double calculateMonthDifference(Date begin, Date end){
		Calendar start = Calendar.getInstance();
		Calendar stop =  Calendar.getInstance();
		double monthDifference = 0;
		
		if(begin.after(end)){
			start.setTime(end);
			stop.setTime(begin);
		}
		else if(begin.before(end)){
			start.setTime(begin);
			stop.setTime(end);
		}
		else{
			return 0;
		}
		
		monthDifference = (stop.get(Calendar.YEAR) - start.get(Calendar.YEAR))*12;
		double stopMonth = (double) stop.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
		double startMonth = (double) start.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
		
		if(stop.get(Calendar.DATE) != stop.getActualMaximum(GregorianCalendar.DAY_OF_MONTH)){
			monthDifference -= 1;
		}
		
		return monthDifference + (stop.get(Calendar.MONTH) - start.get(Calendar.MONTH)) 
			+ (startMonth - start.get(Calendar.DATE))/startMonth + stop.get(Calendar.DATE)/stopMonth;
	}
	
	public static double parseNumberFormat(String currency) {
		try {
			NumberFormat nf = new DecimalFormat("#,##0.##");
			return nf.parse(currency).doubleValue();
		} catch (Exception e) {
			//logger.error("Error parsing currency string: " + currency, e);
			return 0.0;
		}
	}
	
	public static boolean checkColorCode(String color){
		if(color.length() != 3){
			if(color.length() != 6)
				return false;
		}
		
		List<Character> colorList = new ArrayList<Character>();
		
		colorList.add('0');colorList.add('1');colorList.add('2');
		colorList.add('3');colorList.add('4');colorList.add('5');
		colorList.add('6');colorList.add('7');colorList.add('8');
		colorList.add('9');colorList.add('A');colorList.add('B');
		colorList.add('C');colorList.add('D');colorList.add('E');
		colorList.add('F');
		
		for(int i=0; i<color.length(); i++){
			char c = Character.toUpperCase(color.charAt(i));
			
			if(!colorList.contains(c))
				return false;
		}
		
		return true;
	}
	
	public static String trimDoubleString(String value) throws ParseException{
		NumberFormat nf = new DecimalFormat("#,##0.##");
		
		return nf.parse(value).toString();
	}
	
	public static Double roundUpTo2DecimalPlace(Double value){
		DecimalFormat df = new DecimalFormat("#0.00");		
		Double baseValue = Double.parseDouble(df.format(value));
		
		if(value > baseValue){
			return value + 0.01;
		}
		else{
			return baseValue;
		}
	}
}
